// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

namespace SnapObjects.Data
{
    internal class EmbeddedLoadable<TModel>
        : IEmbeddedLoadable<TModel>
    {
        private readonly ModelLoadable<TModel> _modelLoadable;

        public EmbeddedLoadable(
            DataContext context,
            ModelSelectBuilder modelSelectBuilder,
            TModel model,
            IReadOnlyList<IAdoDbParameter> parameters)
        {
            _modelLoadable = new ModelLoadable<TModel>(
                            context,
                            modelSelectBuilder,
                            model,
                            parameters);
        }

        /// <summary>
        ///     Get a reference to the master model object which is passed in as an argument when the 
        ///     ISqlModelMapper.TrackMaster method is called.
        /// </summary>
        public TModel MasterModel => _modelLoadable.MasterModel;

        /// <summary>
        ///     Loads data for the specified embedded property in TModel for all rows. If the ModelEmbedded attribute 
        ///     is applied in the property, the property will use the SQL query(defined in the detail model class 
        ///     specified by the ModelType property of the ModelEmbedded attribute) to retrieve data from database.
        ///     The cascade parameter can be used to decide whether to retrieve data for the embedded properties 
        ///     in the detail model or the granddetail model.
        /// </summary>
        /// <param name="property">
        ///     An embedded property of TModel class.
        ///     This property is specified by an expression.
        /// </param>
        /// <param name="cascade">
        ///     Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be used 
        ///     to decide whether to retrieve data for the embedded properties in the detail model or the granddetail
        ///     model. See master-detail-granddetail for more info. The default value is false.
        /// </param>
        /// <returns>
        ///     Returns the current <see cref="IEmbeddedLoadable{TModel}"/> object whose methods can be used to further obtain 
        ///     the data result set or perform data operations such as embedded queries.
        /// </returns>
        public IEmbeddedLoadable<TModel> Include(Expression<Func<TModel, object>> property, bool cascade = false)
        {
            _modelLoadable.Include(property, cascade);

            return this;
        }

        public async Task<IEmbeddedLoadable<TModel>> IncludeAsync(
            Expression<Func<TModel, object>> property, 
            bool cascade = false, 
            CancellationToken cancellationToken = default)
        {
            await _modelLoadable.IncludeAsync(property, cascade, cancellationToken);

            return this;
        }

        /// <summary>
        ///     Loads data for the embedded properties in TModel for all rows. If the ModelEmbedded attribute is applied 
        ///     in the property, the property will use the SQL query(defined in the detail model class specified by the 
        ///     ModelType property of the ModelEmbedded attribute) to retrieve data from database.The cascade parameter 
        ///     can be used to decide whether to retrieve data for the embedded properties in the detail model or the 
        ///     granddetail model.
        /// </summary>
        /// <param name="cascade">
        ///     Only when the ModelEmbedded attribute is applied in the property, the cascade parameter can be used to 
        ///     decide whether to retrieve data for the embedded properties in the detail model or the granddetail model. 
        ///     See master-detail-granddetail for more info.The default value is false.
        /// </param>
        /// <returns>
        ///     Returns an <see cref="IEmbeddedLoadable{TModel}"/> object whose methods can be used to further obtain the data result
        ///     set or perform data operations such as embedded queries.
        /// </returns>
        public IEmbeddedLoadable<TModel> IncludeAll(bool cascade = false)
        {
            _modelLoadable.IncludeAll(cascade);

            return this;
        }

        public async Task<IEmbeddedLoadable<TModel>> IncludeAllAsync(bool cascade = false, CancellationToken cancellationToken = default)
        {
            await _modelLoadable.IncludeAllAsync(cascade, cancellationToken);

            return this;
        }
    }
}
